#ifndef __K_MEDIAN__
#define __K_MEDIAN__

#pragma once
#include <map>
#include <vector>
#include <tuple>
#include <iostream>
#include <string>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <set>
#include <unordered_set>

namespace wh
{
	using fac_ref_dist_map = std::map<int, std::map<int, double>>;
	using ref_nearest_dist_map = std::map<int, double>;
	void check_file(const std::ifstream& fin, const std::string & name);
	void check_file(const std::ofstream& fout, const std::string& name);
	void eat_line(std::istream& fin);
	void print_dist(const fac_ref_dist_map& fac_ref_dist, const std::vector<std::tuple<int, int, int, double, double, double>>& ref_info, std::map<int, double>& dist_map);
	void print_prob(std::vector<std::tuple<int, int, int, double, double, double>>& ref_info);

	/**************** struct Config************************************
	/*
	/* 定义一个结构体专门用来存储配置文件读入的信息
	/*
	/**************** struct Config************************************/
	struct Config
	{
		std::string edge_file, facility_file, candidate_file, refloc_file, result_file, fac_id, time_file;  // fac_id 记录的是当前选出的设施编号集合
		bool is_directed_graph;
		int K;
		double rate;  // 记录近似率，如果为 0.0 ，则是没有设置，利用默认值

		// 构造函数
		Config() :is_directed_graph(false), K(0), rate(0.0) {};
		Config(const std::string& e, const std::string& f, const std::string& c, const std::string& ref, const std::string& res, bool directed = false, int k = 0)
			:edge_file(e), facility_file(f), candidate_file(c), refloc_file(ref), result_file(res), is_directed_graph(directed), K(k) {};
		~Config() {};
		// 普通成员函数
		void init(const std::string& config_file);
	};

	/**************** 暂存facility 和 candidate的信息的结构 ************************************
	/*
	/* 定义一个 map 结构暂存设备和候选位置的信息，在程序开始时就读入
	/*
	/**************** 暂存facility 和 candidate的信息的结构 ***********************************/
	enum facility_state { Facility, Candidate };
	using facility_info_map = std::map<int, std::tuple<int, int, double, double >>; // 键：设备id，值：边的起点id
																	         // 边的终点id，起点距离，终点距离
	using candidate_info_map = facility_info_map; // 键：候选位置id，值的含义与上面相同
	using reference_info_list = std::vector<std::tuple<int, int, int, double, double, double>>; //id,vs_id,ve_id,vs_dist,ve_dist,prob

	double fast_greedy(std::map<int, double>& dist_map, wh::fac_ref_dist_map& fac_ref_dist, const wh::reference_info_list& ref_info, wh::ref_nearest_dist_map& dist_old, wh::ref_nearest_dist_map& dist_new, std::vector<int>& r_change, std::set<int>& saved_f, const int times, const std::string result_file_path, std::unordered_set<int>& candidate_id, std::vector<std::pair<int, double>>& record_facility);

	double fast_greedy_assistant(std::map<int, double>& dist_map, wh::fac_ref_dist_map& fac_ref_dist, const wh::reference_info_list& ref_info, wh::ref_nearest_dist_map& dist_old, wh::ref_nearest_dist_map& dist_new, std::set<int>& saved_f, int i, const int times, std::ofstream& fout, std::vector<int>& r_change);

	void transfer_fac_to_can(wh::facility_info_map& facility_info, wh::candidate_info_map& candidate_info, const std::set<int>& saved_f);
	double get_dist(const std::map<int, std::pair<int, double>>& ref_dist,const reference_info_list& ref_info);

}

#endif
